package cn.com.tarotframework.config.api;

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.SpringDocConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

/**
 * copyright (C), 2022, 塔罗牌基础架构
 *
 * @program tarot-openapi-spring-boot-starter
 * @description OpenApi配置类
 * @author Jiang Xincan
 * @version 0.0.1
 * @create 2022/5/20 18:54
 **/
@Slf4j
@Configuration
@EnableConfigurationProperties(TarotOpenApiProperties.class)
public class TarotOpenApiConfiguration {

    // 获取应用名称
    @Value("${spring.application.name: tarot}")
    private String applicationName;

    // 获取应用版本
    @Value("${tarot.version: 1.0.0-SNAPSHOT}")
    private String tarotVersion;

    // 注入spring容器上下文
    private final ApplicationContext applicationContext;

    // 注入自定义openapi配置参数
    private final TarotOpenApiProperties tarotOpenApiProperties;


    /**
     *  构造器注入本类属性参数
     * @param applicationContext spring上下文
     * @param tarotOpenApiProperties 自定义open配置参数类
     * @author xincan
     * @date 2023/1/12 16:07
     */
    @Autowired
    public TarotOpenApiConfiguration(ApplicationContext applicationContext, TarotOpenApiProperties tarotOpenApiProperties) {
        this.applicationContext = applicationContext;
        this.tarotOpenApiProperties = tarotOpenApiProperties;
    }

    /**
     * 自动装载 tarotOpenApiService bean,处理分组api【除第一个GroupConfig分组配置不加载之外，其他分组都加载】，一下两个条件必须同时存在
     * 条件判断：如果tarot.openapi.group中，enabled属性值为true，则加载该bean
     * 条件判断：如果自定义
     * 条件判断：如果TarotOpenApiService实现类存在，则加载该bean
     * @author xincan
     * @date 2023/1/12 16:09
     * @return cn.com.tarotframework.config.api.TarotOpenApiService
     */
    @Bean
    @ConditionalOnProperty(prefix = "tarot.openapi.group", name = "enabled", havingValue = "true")
    @Conditional(TarotConditionalOnAutoGroupApi.class)
    @ConditionalOnMissingBean(TarotOpenApiService.class)
    public TarotOpenApiService tarotOpenApiService() {
        this.tarotOpenApiProperties.setApplicationName(this.applicationName);
        this.tarotOpenApiProperties.setVersion(this.tarotVersion);
        TarotOpenApiService tarotOpenApiBean = new TarotOpenApiService(applicationContext, tarotOpenApiProperties);
        tarotOpenApiBean.initOpenApi();
        return tarotOpenApiBean;
    }

    /**
     * 自动装载 groupedOpenApi bean,处理分组api【只加载第一个GroupConfig分组配置】，一下两个条件必须同时存在
     * 条件判断：如果tarot.openapi.group中，enabled属性值为true，则加载该bean
     * @author xincan
     * @date 2023/1/12 16:16
     * @return org.springdoc.core.GroupedOpenApi
     */
    @Bean
    @ConditionalOnProperty(prefix = "tarot.openapi.group", name = "enabled", havingValue = "true")
    public GroupedOpenApi groupedOpenApi(){
        SpringDocConfigProperties.GroupConfig groupConfig = this.tarotOpenApiProperties.getGroup().getGroupConfigs().get(0);
        return GroupedOpenApi.builder()
                .group(groupConfig.getGroup())
                .pathsToMatch(groupConfig.getPathsToMatch().toArray(new String[0]))
                .packagesToScan(groupConfig.getPackagesToScan().toArray(new String[0]))
                .build();
    }

    /**
     * 自动装载：默认OpenAPI基础DOC文档
     *
     * @author xincan
     * @date 2023/1/12 16:18
     * @return io.swagger.v3.oas.models.OpenAPI
     */
    @Bean
    public OpenAPI openAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title(this.applicationName.toUpperCase() + " RESTFUL APIS")
                        .description(this.tarotOpenApiProperties.getDescription())
                        .version(this.tarotVersion)
                        .contact(new Contact()
                                .name(this.tarotOpenApiProperties.getContact().getName())
                                .url(this.tarotOpenApiProperties.getContact().getUrl())
                                .email(this.tarotOpenApiProperties.getContact().getEmail())
                        )
                        .license(new License()
                                .name(this.tarotOpenApiProperties.getLicense().getName())
                                .url(this.tarotOpenApiProperties.getLicense().getUrl())
                        )
                )
                .externalDocs(new ExternalDocumentation()
                        .description(this.tarotOpenApiProperties.getExternalDocs().getDescription())
                        .url(this.tarotOpenApiProperties.getExternalDocs().getUrl())
                );
    }

}
